在觀察電池最佳化設定的問題是否被排除的同時,讓我們來解決通知重複的 bug 吧!
筆者調查了官方文件,發現我們當初透過 createTriggerNotification 建立任務時,並沒有提供 id。
此外,如果有 id 已經通知排程了,則 createTriggerNotification 的效果會是 update 既有的 id,可以說這個 API 其實是 upsert 的行為。
若我們不提供 id,根據官方的文件是隨機 gen 出來的:
Defaults to a random string if not provided.
筆者亦發現有取得目前所有建立的通知任務 id 的 API: getTriggerNotificationIds。
讓我們在 notification.js 中的 setNotificationByWeekDay 加入這段驗證一下:
const ids = await notifee.getTriggerNotificationIds();
console.log(ids.length);
要記得把 fuction 改成 async。
refresh app 幾次,印出來後我們可以看到:
14 筆的幅度在增長,符合我們先前的推斷理由是, setNotificationByWeekDay 會在一週七天,分別建立早上以及晚上的通知:
for (const predict of nightPrediction) {
const {weekday, time} = predict;
// night notification
onCreateTriggerNotificationByWeekday(time, weekday);
// morning notification
onCreateTriggerNotificationByWeekday(dayPredcition, weekday);
}
所以每次 app 刷新時, useEffect 內的 setNotificationByWeekDay 都會在既有的任務 list 中加入 14 筆通知排程。
筆者決定加入通知 id,來讓每次 app 刷新只是 update 既有的任務,而非 create 新的任務。
筆者希望簡單就好,快速決定是 $weekday-$nightorday 的格式。
首先我們在 onCreateTriggerNotificationByWeekday 中加入第三個參數 isNight,以及以下邏輯:
const customizedNotificationId =
isNight === undefined
? null
: isNight
? `${weekday}-night`
: `${weekday}-day`;
onCreateTriggerNotification(
absoluteTimeInMs,
message,
customizedNotificationId,
);
例如以週二早上為例,我們 weekday 傳入的值是 tue,isNight 傳入的是 false,就會組出 tue-day。同時也保有如果沒有傳入 isNight 時,就委由底層邏輯幫忙產出 id 的彈性。
我們將自製的 id 傳入真正 call notifee api 的 onCreateTriggerNotification 中。同時,我們在 setNotificationByWeekDay 加入第三個參數:
for (const predict of nightPrediction) {
const {weekday, time} = predict;
// night notification
onCreateTriggerNotificationByWeekday(time, weekday, true);
// morning notification
onCreateTriggerNotificationByWeekday(dayPredcition, weekday, false);
}
進一步,同時筆者也實作了上層 function 沒有提供 id 時的備案,然而途中碰到一些問題,記錄如下:
筆者首先嘗試的是 uuid,
id: id || uuidv4(),
但得到以下錯誤訊息:
crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported
找到了這篇討論:https://github.com/uuidjs/uuid/issues/416
快速瀏覽過去,心中有已想好備案,問題看似無法馬上排除,所以決定不用 uuid 套件。
使用時,碰到以下問題:
ReferenceError: Property 'crypto' doesn't exist
怎麼都是 crypto 相關的,筆者決定有空再來調查亂數產生的 id。
由於目前沒有其他需求,只是要做到通知任務不重複以及管理通知而已,故筆者的 workaround 為使用 Date 的 ISOString:
id: id || new Date().toISOString(),
最終底層的 id 就會是客製化後傳入的,不然就是直接使用 Date ISOString 來作為 ID。
export async function onCreateTriggerNotification(
time: String,
message: String,
id: String | null,
) {
...
// Create a trigger notification
await notifee.createTriggerNotification(
{
id: id || new Date().toISOString(),
title: '關門通知',
body: message || '樓下關門即將在 10 分鐘內發生',
android: {
channelId,
pressAction: {
id: 'default',
},
},
},
trigger,
);
}

幾次刷新後,任務數目仍然維持一樣的,可以看到 notifee 幫忙產生的 id、實作過程中以日期產生的 id 以及我們客製的 id 同時共存。

bug 解決!
筆者先前沒發現文件有提及循環通知。
我們可以在 trigger 加入循環通知週期 (repeatFrequency):
const trigger: TimestampTrigger = {
type: TriggerType.TIMESTAMP,
timestamp: time,
repeatFrequency: RepeatFrequency.WEEKLY,
};
筆者決定以此實作,並刪除原先 useEffect 中設定循環通知的段落:
// trigger every 7 days
setInterval(setNotificationByWeekDay, sevenDaysInterval);
初步看下來這個 bug 算是解決了,而且還優化了循環通知邏輯,讓我們使用幾天驗證一下吧!
今天收工!